#pragma once

#include "Common.hpp"
#include "InetAddr.hpp"

//模板方法模式建立继承体系
class Socket_t
{
public: // 纯虚方法
    virtual void Socket() = 0; // 创建套接字
    virtual void Bind(uint16_t port) = 0; // 绑定套接字
    virtual void Listen(int backlog) = 0; // 监听
    virtual std::shared_ptr<Socket_t> Accept(InetAddr* client) = 0; // 接受客户端连接
    virtual void Close() = 0; // 关闭套接字
    virtual int Recv(std::string* out) = 0; // 接收消息
    virtual int Send(const std::string& in) = 0; // 发送消息
    virtual int GetFd() = 0; // 获取文件描述符
public: // 模板方法
    Socket_t() = default;

    //服务器创建套接字，并使其处于监听状态
    void BuildListenSocket(uint16_t port, int backlog = 8)
    {
        Socket();
        Bind(port);
        Listen(backlog);
    }
};

class TcpSocket_t : public Socket_t
{
public:
    TcpSocket_t() = default;

    TcpSocket_t(int fd) : _sockfd(fd) {}

    //创建套接字
    virtual void Socket() override
    {
        _sockfd = socket(AF_INET, SOCK_STREAM, 0);
        if(_sockfd < 0)
        {
            std::cerr << "socket error" << std::endl;
            exit((int)exit_code::SOCKET_ERR);
        }
        std::cout << "socket success" << std::endl;
    }

    //绑定套接字
    virtual void Bind(uint16_t port) override
    {
        InetAddr addr(port); // 针对服务器绑定任意地址
        int n = bind(_sockfd, addr.NetAddrPtr(), addr.AddrLen());
        if(n < 0)
        {
            std::cerr << "bind error" << std::endl;
            exit((int)exit_code::BIND_ERR);
        }
        std::cout << "bind success" << std::endl;
    }

    //监听套接字
    virtual void Listen(int backlog) override
    {
        int n = listen(_sockfd, backlog);
        if(n < 0)
        {
            std::cerr << "listen error" << std::endl;
            exit((int)exit_code::LISTEN_ERR);
        }
        std::cout << "listen success" << std::endl;
    }

    //接受客户端连接
    virtual std::shared_ptr<Socket_t> Accept(InetAddr* client) override
    {
        struct sockaddr_in addr;
        socklen_t len = sizeof(addr);
        int fd = accept(_sockfd, (sockaddr*)&addr, &len);
        if(fd < 0)
        {
            std::cout << "accept warning" << std::endl;
            return nullptr;
        }
        std::cout << "accept success" << std::endl;
        client->SetAddr(addr);
        return std::make_shared<TcpSocket_t>(fd);
    }

    //关闭套接字
    virtual void Close() override
    {
        if(_sockfd > 0) close(_sockfd);
    }

    //接收消息 -- 由子进程执行
    virtual int Recv(std::string* out) override
    {
        char buff[8192];
        ssize_t len = recv(_sockfd, buff, sizeof(buff) - 1, 0);
        if(len > 0)
        {
            buff[len] = '\0';
            *out += buff;
        }
        return len;
    }

    //发送消息 -- 由子进程执行
    virtual int Send(const std::string& in) override
    {
        return send(_sockfd, in.c_str(), in.size(), 0);
    }

    //获取文件描述符
    virtual int GetFd() override
    {
        return _sockfd;
    }
private:
    int _sockfd = -1; // 网络文件描述符
};